﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace Rainbow.utils
{
    public class SHCollection<T>
    //where T : ICloneable
    {
        //  protected readonly object lockerObj = new object();

        protected ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();

        public List<T> dataList { get; }

        public virtual bool Equals(T obj, object key)
        {
            return false;
        }

        public virtual void CopyTo(T src, T dst)
        {

        }

        public SHCollection()
        {
            dataList = new List<T>();
        }

        //public SHCollection(SHCollection<T> collection)
        //{
        //    dataList = new List<T>();
        //    collection.ForEach(x =>
        //    {
        //        T data = (T)x.Clone();
        //        dataList.Add(data);
        //    });
        //    // foreach(var v in collection)
        //}

        public int Count()
        {
            rwLock.EnterReadLock();

            try
            {
                return dataList.Count;
            }
            finally
            {
                rwLock.ExitReadLock();
            }
        }

        public List<T> Where(Func<T, bool> func)
        {
            List<T> rn = new List<T>();

            rwLock.EnterReadLock();
            try
            {
                foreach (var v in dataList)
                {
                    if (func(v))
                    {
                        rn.Add(v);
                    }
                }
            }
            finally
            {
                rwLock.ExitReadLock();
            }


            return rn;
        }

        public bool Exists(Predicate<T> predicate)
        {
            rwLock.EnterReadLock();

            try
            {
                return dataList.Exists(predicate);
            }
            finally
            {
                rwLock.ExitReadLock();
            }
        }
        public void ForEach(Func<T, bool> func)
        {
            rwLock.EnterReadLock();

            try
            {
                foreach (var v in dataList)
                {
                    if (func(v)) break;
                }
            }
            finally
            {
                rwLock.ExitReadLock();
            }
        }

        public int Update(object key, T newObj)
        {
            int rn = 0;

            rwLock.EnterWriteLock();

            try
            {
                T oldObj = dataList.Where(x => Equals(x, key)).FirstOrDefault();
                if (oldObj != null)
                {
                    CopyTo(newObj, oldObj);
                }

            }
            catch (Exception)
            {
                rn = -1;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return rn;
        }

        public int Delete(T obj)
        {
            int rn = 0;

            rwLock.EnterWriteLock();
            try
            {
                dataList.Remove(obj);
            }
            catch (Exception)
            {
                rn = -1;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return rn;
        }

        public int Delete(object key)
        {
            int rn = 0;
            rwLock.EnterWriteLock();
            try
            {

                T s = dataList.Where(x => Equals(x, key)).FirstOrDefault();
                if (s != null) dataList.Remove(s);
            }
            catch (Exception)
            {
                rn = -1;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return rn;
        }

        public int Add(T obj)
        {
            int rn = 0;
            rwLock.EnterWriteLock();
            try
            {
                dataList.Add(obj);
            }
            catch (Exception)
            {
                rn = -1;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return rn;
        }

        public T Find(object key)
        {
            T rn = default(T);

            rwLock.EnterReadLock();
            try
            {
                rn = dataList.Where(x => Equals(x, key)).FirstOrDefault();
            }
            catch (Exception)
            {
                rn = default(T);
            }
            finally
            {
                rwLock.ExitReadLock();
            }

            return rn;
        }

        public T GetCopy(object key)
        {
            T rn = default(T);

            rwLock.EnterReadLock();
            try
            {
                T src = dataList.Where(x => Equals(x, key)).FirstOrDefault();
                CopyTo(src, rn);
            }
            catch (Exception)
            {
                rn = default(T);
            }
            finally
            {
                rwLock.ExitReadLock();
            }

            return rn;
        }

        public void Clear()
        {
            rwLock.EnterWriteLock();
            try
            {

                dataList.Clear();
            }
            catch (Exception)
            {
            }
            finally
            {
                rwLock.ExitWriteLock();
            }
        }

        public List<T> ToList()
        {
            List<T> rn = null;

            rwLock.EnterReadLock();
            try
            {
                rn = dataList.ToList();
            }
            catch (Exception)
            {
                rn = null;
            }
            finally
            {
                rwLock.ExitReadLock();
            }

            return rn;
        }
    }


    //public class SHObservableCollection<T> : INotifyPropertyChanged
    //{
    //    protected readonly object lockerObj = new object();
    //    private ObservableCollection<T> m_dataList;
    //    public ObservableCollection<T> dataList
    //    {
    //        get { return m_dataList; }
    //        set
    //        {
    //            this.m_dataList = value;
    //            NotifyPropertyChanged();
    //        }
    //    }

    //    public SHObservableCollection()
    //    {
    //        dataList = new ObservableCollection<T>();
    //    }

    //    public event PropertyChangedEventHandler PropertyChanged;
    //    public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    //    {
    //        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    //    }

    //    public virtual bool Equals(T obj, object key)
    //    {
    //        return false;
    //    }

    //    public virtual void CopyTo(T src, T dst)
    //    {

    //    }

    //    //public SHObservableCollection(SHObservableCollection<T> collection)
    //    //{
    //    //    dataList = new ObservableCollection<T>();
    //    //    collection.ForEach(x =>
    //    //    {
    //    //        T data = (T)x.Clone();
    //    //        dataList.Add(data);
    //    //    });
    //    //    // foreach(var v in collection)
    //    //}

    //    public int Count()
    //    {
    //        lock (lockerObj)
    //        {
    //            return dataList.Count;
    //        }
    //    }

    //    public void ForEach(Func<T, bool> func)
    //    {
    //        lock (lockerObj)
    //        {
    //            foreach (var v in dataList)
    //            {
    //                if (func(v)) break;
    //            }
    //        }
    //    }

    //    public int Update(object key, T newObj)
    //    {
    //        int rn = 0;
    //        try
    //        {
    //            lock (lockerObj)
    //            {
    //                T oldObj = dataList.Where(x => Equals(x, key)).FirstOrDefault();
    //                if (oldObj != null)
    //                {
    //                    CopyTo(newObj, oldObj);
    //                }
    //            }
    //        }
    //        catch (Exception e)
    //        {
    //            rn = -1;
    //        }

    //        return rn;
    //    }

    //    public int Delete(T obj)
    //    {
    //        int rn = 0;
    //        try
    //        {
    //            lock (lockerObj)
    //            {
    //                dataList.Remove(obj);
    //            }
    //        }
    //        catch (Exception e)
    //        {
    //            rn = -1;
    //        }

    //        return rn;
    //    }

    //    public int Delete(object key)
    //    {
    //        int rn = 0;
    //        try
    //        {
    //            lock (lockerObj)
    //            {
    //                T s = dataList.Where(x => Equals(x, key)).FirstOrDefault();
    //                if (s != null) dataList.Remove(s);
    //            }
    //        }
    //        catch (Exception e)
    //        {
    //            rn = -1;
    //        }

    //        return rn;
    //    }

    //    public int Add(T obj)
    //    {
    //        int rn = 0;
    //        try
    //        {
    //            lock (lockerObj)
    //            {
    //                dataList.Add(obj);
    //            }
    //        }
    //        catch (Exception e)
    //        {
    //            rn = -1;
    //        }

    //        return rn;
    //    }

    //    public T Find(object key)
    //    {
    //        T rn = default(T);
    //        try
    //        {
    //            lock (lockerObj)
    //            {
    //                rn = dataList.Where(x => Equals(x, key)).FirstOrDefault();
    //            }
    //        }
    //        catch (Exception e)
    //        {
    //            rn = default(T);
    //        }

    //        return rn;
    //    }

    //    public void Clear()
    //    {
    //        try
    //        {
    //            lock (lockerObj)
    //            {
    //                dataList.Clear();
    //            }
    //        }
    //        catch (Exception e)
    //        {
    //        }
    //    }
    //}
}
